package com.gitee.loyo.jdbc

import java.math.BigDecimal
import java.sql.Connection
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.util.*
import javax.sql.DataSource
import kotlin.reflect.KClass

object JDBC{
    private const val DEFAULT_DS = "default"

    internal val parameterHandlerMap: MutableMap<KClass<out Any>, ParameterHandler<out Any>> = HashMap()
    internal val resultSetHandlerMap: MutableMap<KClass<out Any>, ResultSetHandler<*>> = HashMap()
    private var dsMap: Map<String, Ds> = emptyMap()

    fun init(ds: DataSource){
        init(Ds(ds))
    }

    fun init(ds: Ds){
        init(DEFAULT_DS to ds)
    }

    fun init(vararg entry: Pair<String, Ds>){
        parameterHandlerMap[Short::class] = ParameterHandler.SHORT
        parameterHandlerMap[Int::class] = ParameterHandler.INT
        parameterHandlerMap[Long::class] = ParameterHandler.LONG
        parameterHandlerMap[Float::class] = ParameterHandler.FLOAT
        parameterHandlerMap[Double::class] = ParameterHandler.DOUBLE
        parameterHandlerMap[Boolean::class] = ParameterHandler.BOOLEAN
        parameterHandlerMap[String::class] = ParameterHandler.STRING
        parameterHandlerMap[Date::class] = ParameterHandler.DATE
        parameterHandlerMap[LocalDate::class] = ParameterHandler.LOCAL_DATE
        parameterHandlerMap[LocalTime::class] = ParameterHandler.LOCAL_TIME
        parameterHandlerMap[LocalDateTime::class] = ParameterHandler.LOCAL_DATE_TIME
        parameterHandlerMap[BigDecimal::class] = ParameterHandler.BIG_DECIMAL
        parameterHandlerMap[ByteArray::class] = ParameterHandler.BYTE_ARRAY
        parameterHandlerMap[Array<Int>::class] = ParameterHandler.INT_ARRAY
        parameterHandlerMap[Array<String>::class] = ParameterHandler.STRING_ARRAY
        parameterHandlerMap[Array<Double>::class] = ParameterHandler.BIG_DECIMAL_ARRAY

        resultSetHandlerMap[Short::class] = ResultSetHandler.SHORT
        resultSetHandlerMap[Int::class] = ResultSetHandler.INT
        resultSetHandlerMap[Long::class] = ResultSetHandler.LONG
        resultSetHandlerMap[Float::class] = ResultSetHandler.FLOAT
        resultSetHandlerMap[Double::class] = ResultSetHandler.DOUBLE
        resultSetHandlerMap[Boolean::class] = ResultSetHandler.BOOLEAN
        resultSetHandlerMap[String::class] = ResultSetHandler.STRING
        resultSetHandlerMap[Date::class] = ResultSetHandler.DATE
        resultSetHandlerMap[LocalDate::class] = ResultSetHandler.LOCAL_DATE
        resultSetHandlerMap[LocalTime::class] = ResultSetHandler.LOCAL_TIME
        resultSetHandlerMap[LocalDateTime::class] = ResultSetHandler.LOCAL_DATE_TIME
        resultSetHandlerMap[BigDecimal::class] = ResultSetHandler.BIG_DECIMAL
        resultSetHandlerMap[ByteArray::class] = ResultSetHandler.BYTE_ARRAY
        resultSetHandlerMap[Array<Int>::class] = ResultSetHandler.INT_ARRAY
        resultSetHandlerMap[Array<String>::class] = ResultSetHandler.STRING_ARRAY
        resultSetHandlerMap[Array<Double>::class] = ResultSetHandler.BIG_DECIMAL_ARRAY
        resultSetHandlerMap[Array<Any>::class] = ResultSetHandler.OBJECT_ARRAY

        this.dsMap = entry.toMap()
    }

    fun ds(): Ds?{
        return dsMap.values.firstOrNull()
    }

    fun putParameterHandler(type: KClass<Any>, handler: ParameterHandler<Any>){
        parameterHandlerMap[type] = handler
    }

    fun putResultSetHandler(type: KClass<Any>, handler: ResultSetHandler<Any>){
        resultSetHandlerMap[type] = handler
    }

    operator fun get(dsName: String): Ds{
        return dsMap[dsName]?:throw NullPointerException("未找到数据库${dsName}")
    }

    fun <T> open(transaction: Int = Connection.TRANSACTION_NONE, fn: (Conn) -> T): T{
        if(this[DEFAULT_DS] == null)
            throw NullPointerException("未找到数据库${DEFAULT_DS}")
        return this[DEFAULT_DS].open(transaction, fn)
    }

}